﻿
using Boilen.Primitives.Members;
using System.Collections.Generic;


namespace Boilen.Primitives.Implementers {

    /// <summary>
    /// Implements an interface or base class, such as INotifyPropertyChanged.
    /// </summary>
    /// <typeparam name="T">The type of the interface.</typeparam>
    public abstract class InterfaceImplementer<T> : Implementer<T> {

        /// <summary>
        /// Gets or sets a value indicating whether <see cref="InterfaceMembers"/> should be automatically wrapped in a group.
        /// </summary>
        protected virtual bool CreateGroup { get { return true; } }

        /// <summary>
        /// Gets the inheritance declarations for all implemented interfaces.
        /// </summary>
        protected virtual IEnumerable<InheritanceMember> ImplementedInterfaces {
            get { yield return new InheritanceMember( this.Name ); }
        }

        /// <summary>
        /// Gets the implementation members for the interface.
        /// </summary>
        protected abstract IEnumerable<Member> InterfaceMembers { get; }

        /// <inheritdoc/>
        protected override bool EnsureDescription { get { return false; } }


        /// <inheritdoc/>
        protected InterfaceImplementer( PartialType parent, string name )
            : base( parent, name, XmlDocumentation.GetSummary( typeof( T ) ) ) { }

        /// <inheritdoc/>
        protected InterfaceImplementer( PartialType parent )
            : this( parent, parent.TypeRepository.GetTypeName( typeof( T ) ) ) { }


        /// <inheritdoc/>
        protected sealed override IEnumerable<Member> GetMembers( ) {
            foreach( var inherit in this.ImplementedInterfaces )
                yield return inherit;

            var group = new MemberGroup( this.Name + " Members" );
            foreach( var member in this.InterfaceMembers ) {
                if( this.CreateGroup )
                    group.Members.Add( member );
                else
                    yield return member;
            }

            if( this.CreateGroup )
                yield return group;
        }

    }

}
